#include "glWidget.h"

#include "fenetrePrincipale.h"
#include "moteurGraphique.h"
#include "moteurJeu.h"

GLWidget::GLWidget(FenetrePrincipale *fenetrePrincipale) : QGLWidget(fenetrePrincipale)  {
    // DEBUG
    ofstream file("debug.log", ios::out | ios::trunc);
    file.close();


    parent = fenetrePrincipale;
    picking = false;

    if(QGLFormat::hasOpenGL()) {

    }
}

void GLWidget::initializeGL() {
    qglClearColor(Qt::blue);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT,GL_DIFFUSE);

    //glEnable(GL_NORMALIZE);

    glEnable(GL_LIGHTING);

    GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0};
    GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat position[] = {8.0, 8.0, 20.0, 0.0};

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glLightfv(GL_LIGHT0, GL_POSITION, position);

    glEnable(GL_LIGHT0);

    // Initialisation des différentes listes permettant de dessiner les pièces
    Case::creerListe();
    Tour::creerListe();
    Cavalier::creerListe();
    Fou::creerListe();
    Reine::creerListe();
    Roi::creerListe();
    Pion::creerListe();
}

void GLWidget::resizeGL(int width, int height) {
    glViewport(0,0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(75, (double)(width/height), 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
}

void GLWidget::paintGL() {
    // ??? a modifier ?
    if ( (parent->getParent()->moteurJeu == NULL)  || (((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie() == NULL) ) {
        double r,g,b;
        bool blanc = false;
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(8, 4, 15, 8, 8, 0, 0, 1, 0);

        for(int i=0; i<8; i++) {
            for(int j=0; j<8; j++) {
                if(blanc) {
                    r = 1.0;
                    g = 1.0;
                    b = 1.0;
                }
                else {
                    r = 0.0;
                    g = 0.0;
                    b = 0.0;
                }

                // On sauvegarde la matrice
                glPushMatrix();
                    // Changement de couleur
                    glColor3d(r, g, b);
                    // On déplace le repère
                    glTranslatef(1+2*i, 1+2*j, 0);
                    // On dessine la case
                    glCallList(Case::getLid());
                glPopMatrix();
                blanc = !blanc;
            }
            blanc = !blanc;
        }
        glFlush();
    }
    else {
        double r,g,b;
        bool blanc = false;
        // DEBUG
        ofstream sortie("sortie.txt", ios::out);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(8, 8, 14, 8, 8, 0, 0, 1, 0);

        for(int i=0; i<8; i++) {
            for(int j=0; j<8; j++) {
                if(blanc) {
                    r = 1.0;
                    g = 1.0;
                    b = 1.0;
                }
                else {
                    r = 0.0;
                    g = 0.0;
                    b = 0.0;
                }

                // AFFICHAGE DES CASES
                // On sauvegarde la matrice
                glPushMatrix();
                    // Changement de couleur
                    glColor3d(r, g, b);
                    // On déplace le repère
                    glTranslatef(1+2*i, 1+2*j, 0);
                    // On dessine la case
                    glCallList(Case::getLid());
                glPopMatrix();

                // AFFICHAGES DES DEPLACEMENTS
                glPushMatrix();
                    switch( ((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LireDepl(i,j) ) {
                        // Case active
                        case CASE_ACTUELLE :
                            glColor4d(0.0, 1.0, 0.0, 0.5);
                            glTranslatef(1+2*i, 1+2*j, 0.05);
                            glEnable(GL_BLEND);		// Turn Blending On
                            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                glCallList(Case::getLid());
                            glDisable(GL_BLEND);		// Turn Blending Off
                            break;
                        // Case possible
                        case DEPLACEMENT :
                        case DEPLACEMENT_DOUBLE :
                        case PETIT_ROQUE :
                        case GRAND_ROQUE :
                        case PROMOTION_DEPLACEMENT :
                            glColor4d(0.0, 1.0, 1.0, 0.5);
                            glTranslatef(1+2*i, 1+2*j, 0.05);
                            glEnable(GL_BLEND);		// Turn Blending On
                            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                glCallList(Case::getLid());
                            glDisable(GL_BLEND);		// Turn Blending Off
                            break;
                        // Attaque possible
                        case CAPTURE :
                        case EN_PASSANT :
                        case PROMOTION_CAPTURE :
                            glColor4d(1.0, 1.0, 0.0, 0.5);
                            glTranslatef(1+2*i, 1+2*j, 0.05);
                            glEnable(GL_BLEND);		// Turn Blending On
                            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                glCallList(Case::getLid());
                            glDisable(GL_BLEND);		// Turn Blending Off
                            break;
                        default :
                            break;
                    }
                glPopMatrix();

                // AFFICHAGE DES PIECES
                if(((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LirePlateau(i,j) != NULL) {
                    glPushMatrix();
                        glTranslatef(1+2*i, 1+2*j, 0);
                        if(((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LirePlateau(i,j)->getCouleur() == BLANC) {
                            glRotatef(180, 0, 0, 1);
                            glColor3d(0.8, 0.8, 0.8);
                        }
                        else {
                            glColor3d(0.2, 0.2, 0.2);
                        }
                        glCallList(((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LirePlateau(i,j)->getLid());
                    glPopMatrix();
                }

                // On restaure la matrice
                //glPopMatrix();    // déplacé plus haut

                blanc = !blanc;
            }

            blanc = !blanc;
        }

        glFlush();

        sortie.close();
    }
}

void GLWidget::mousePressEvent(QMouseEvent *event) {
    if (picking)
        traiterPicking(event->x(), event->y());
}

void GLWidget::mouseMoveEvent(QMouseEvent *event) {

}

void GLWidget::mouseDoubleClickEvent(QMouseEvent *event) {

}


void GLWidget::dessinerPicking() {
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(8, 8, 14, 8, 8, 0, 0, 1, 0);

    for(int i=0; i<8; i++) {

        glLoadName(i);

        for(int j=0; j<8; j++) {

            glPushName(j);

            // On sauvegarde la matrice
            glPushMatrix();

                // On déplace le repère
                glTranslatef(1+2*i, 1+2*j, 0);

                // On dessine la case
                glCallList(Case::getLid());

            glPopMatrix();

                if(((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LirePlateau(i,j) != NULL) {
                    glPushMatrix();
                        glTranslatef(1+2*i, 1+2*j, 0);
                        if(((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LirePlateau(i,j)->getCouleur() == BLANC) {
                            glRotatef(180, 0, 0, 1);
                        }
                        glCallList(((MoteurJeu *)(parent->getParent()->moteurJeu))->getPartie()->LirePlateau(i,j)->getLid());
                    glPopMatrix();
                }

            // On restaure la matrice
            //glPopMatrix();    // déplacé plus haut

            glPopName();
        }
    }

}

void GLWidget::traiterPicking(int x, int y) {
    ofstream file("debug.log", ios::app);
    int colonne, ligne;
    float zmin=100.0f;


    GLuint selectBuf[512];
    GLint hits;
    GLint viewport[4];

    glGetIntegerv(GL_VIEWPORT, viewport);

    glSelectBuffer(512, selectBuf);
    glRenderMode(GL_SELECT);

    glInitNames();
    glPushName(0);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPickMatrix((GLdouble) (x), (GLdouble) (viewport[3]-(y)), 5.0, 5.0, viewport);
    gluPerspective(75.0f,(GLfloat)((this->size()).width())/(GLfloat)((this->size()).height()),1.0f,100.0f);

    dessinerPicking();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glFlush();

    hits = glRenderMode(GL_RENDER);

    if (hits==0) {
        // Clic a coté
    }
    else {
        GLuint names;
        GLuint *ptr = (GLuint*) selectBuf;
        for (int i=0; i<hits; i++) {
            names = *ptr;
            //file << "nombre de noms pour ce hit = " << names << endl;
            ptr++;
            file << " z1 egale " << (float) *ptr/0x7fffffff << endl;
            if ((float) *ptr/0x7fffffff < zmin) {   // si plus proche que l'ancien plus proche
                zmin = (float) *ptr/0x7fffffff;
                ptr++;
                //file << " z2 egale " << (float) *ptr/0x7fffffff << endl;
                ptr++;
                //file << " noms : ";
                for (int j=0; j<names; j++) {
                    if (j==0)
                        colonne = *ptr;
                    if (j==1)
                        ligne = *ptr;
                    ptr++;
                }
            }
                //file << endl;
            //}
        }

        // case/piece la plus proche
        file << "Case cliquée : [" << colonne << "," << ligne << "]" << endl;
        Message m(PIECE_CLIQUEE);
        m.ajouterEntier(colonne);
        m.ajouterEntier(ligne);
        parent->getParent()->moteurJeu->envoyerMessage(m);
    }

    file.close();
}

void GLWidget::setPicking(bool picking_on) {
    this->picking = picking_on;
}
